/* 
 * File:   apeDecoder.cpp
 * Author: hao
 * 
 * Created on 2011年5月18日, 上午12:47
 */


#include "apeDecoder.h"

apeDecoder::apeDecoder():pAPEDecompress(NULL){
}

bool apeDecoder::Checking(void* pData, unsigned long long length){
    
    char * tmp = ( char * )pData;
    if( tmp[0] != 'M' || tmp[1] != 'A' || tmp[2] != 'C' ) return false;
    
    pluginIO.setData( (char*)pData, length );
    
    pAPEDecompress = CreateIAPEDecompressEx( &pluginIO );
    
    return true;
}

bool apeDecoder::Decoding(void* pTarget, size_t length, size_t* ReadSize){
    
    
    if( currentBlocks >= endBlocks ) return false;
    
    if( currentBlocks < startBlocks ){
        pAPEDecompress->Seek( startBlocks);
        currentBlocks = startBlocks;
    }
    
    
    unsigned long long BlockCount = length / pAPEDecompress->GetInfo( APE_INFO_BLOCK_ALIGN );
    
    int readBlock;
    
    char * buffer = new char[length];
    
    int ret = pAPEDecompress->GetData( buffer, BlockCount, &readBlock );
    
    if( ret != ERROR_SUCCESS ){
        delete [] buffer;
        return false;
    }
    
    memcpy( pTarget, buffer, readBlock * pAPEDecompress->GetInfo( APE_INFO_BLOCK_ALIGN ) );
    
    delete [] buffer;
    
    currentBlocks += BlockCount;
    
    if( readBlock == 0 ) return false;
    
    *ReadSize = readBlock * pAPEDecompress->GetInfo( APE_INFO_BLOCK_ALIGN );
    
    return true;
    
}

bool apeDecoder::Seek(int Min, int Second, int Frame){
    unsigned long long seekBlocks = (Min * 60 + Second + Frame/75 ) * pAPEDecompress->GetInfo( APE_INFO_SAMPLE_RATE );
    
    currentBlocks += seekBlocks;
    
    return pAPEDecompress->Seek( currentBlocks );
    
}

bool apeDecoder::SetTrack(int Min, int Second, int Frame, int EndMin, int EndSecond, int EndFrame){
    startBlocks = ((unsigned long long) Min * 60 + (unsigned long long) Second + (unsigned long long) Frame / 75 ) * (unsigned long long) pAPEDecompress->GetInfo( APE_INFO_SAMPLE_RATE );

    if (EndMin == -1 || EndSecond == -1 || EndFrame == -1) {
        getTotalTime(&EndMin, &EndSecond, &EndFrame);
    }

    endBlocks = ((unsigned long long) EndMin * 60 + (unsigned long long) EndSecond + (unsigned long long) EndFrame / 75 ) * (unsigned long long) pAPEDecompress->GetInfo( APE_INFO_SAMPLE_RATE );
    
    if( endBlocks > (unsigned long long )pAPEDecompress->GetInfo( APE_INFO_TOTAL_BLOCKS ) )
        endBlocks = (unsigned long long )pAPEDecompress->GetInfo( APE_INFO_TOTAL_BLOCKS );

    currentBlocks = 0;
    
    return true;
}

void apeDecoder::getStatus(unsigned* pFormat, unsigned* pChannels, unsigned* pRate){
    
    *pChannels = pAPEDecompress->GetInfo(APE_INFO_CHANNELS );
    *pFormat = pAPEDecompress->GetInfo( APE_INFO_BITS_PER_SAMPLE );
    *pRate = pAPEDecompress->GetInfo( APE_INFO_SAMPLE_RATE );
    
}

void apeDecoder::getTotalTime(int* pMin, int* pSecond, int* pFrame){
    
    unsigned ms = pAPEDecompress->GetInfo( APE_INFO_LENGTH_MS );
    
    *pMin = ( int )( ms / ( 1000 * 60 ) );
    ms %= 1000 * 60;
    *pSecond = ( int )( ms / 1000 );
    ms %= 1000;
    *pFrame = (int)( ( ( double ) ms / 1000 ) * 75 );
    
}

apeDecoder::~apeDecoder() {
    
    delete pAPEDecompress;
    
}

